package com.stp.yupao.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.stp.yupao.mapper.RecommendHistoryMapper;
import com.stp.yupao.mapper.UserMapper;
import com.stp.yupao.model.domain.RecommendHistory;
import com.stp.yupao.model.domain.User;
import com.stp.yupao.service.RecommendService;
import com.stp.yupao.utils.UserToUserTagRecommender;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service
@RequiredArgsConstructor
public class RecommendServiceImpl implements RecommendService {

    private final UserMapper userMapper;
    private final RecommendHistoryMapper recommendHistoryMapper;

    @Resource
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public Boolean dailyRecommend() {
        //TODO 扩展 可查询近7天内登陆的用户
        List<User> userList = userMapper.selectList(Wrappers.lambdaQuery());
        if(CollUtil.isEmpty(userList)){
            return Boolean.TRUE;
        }
        Integer count = 10;
        Map<Long, List<RecommendHistory>> userRecommendHistoryMap = getUserRecommendHistoryMap(userList.stream().map(User::getId).collect(Collectors.toSet()));
        Gson gson = new Gson();
        for (User user : userList){
            // 获取用户已推荐的人员ID(最近30天内)
            long userId = user.getId();
            List<RecommendHistory> histories = userRecommendHistoryMap.getOrDefault(userId, new ArrayList<>());
            Set<Long> recommendedPersonIds = histories.stream().map(RecommendHistory::getPersonId).collect(Collectors.toSet());

            // 筛选未推荐的人员
            List<User> candidates = userList.stream()
                    .filter(p -> !recommendedPersonIds.contains(p.getId()))
                    .collect(Collectors.toList());

            // 如果没有足够的新人员，重置推荐历史(放宽条件)
            if (candidates.size() < count) {
                candidates = new ArrayList<>(userList);
            }

            List<String> tagList = gson.fromJson(user.getTags(), new TypeToken<List<String>>() {}.getType());
            UserToUserTagRecommender recommender = new UserToUserTagRecommender();
            tagList.forEach(userTag -> {
                recommender.addUserTag(userId, userTag, 1.0);
            });

            // 依次计算所有用户和当前用户的相似度
            candidates.forEach(item -> {
                String userTags = item.getTags();
                // 无标签或者为当前用户自己
                if (StrUtil.isBlank(userTags) || Objects.equals(item.getId(),userId)) {
                    return;
                }
                List<String> userTagList = gson.fromJson(userTags, new TypeToken<List<String>>() {
                }.getType());
                userTagList.forEach(userTag -> {
                    recommender.addUserTag(item.getId(), userTag, 1.0);
                });
            });

            List<Long> userIdList = recommender.recommendUsers(userId, count, CollUtil.newHashSet(userId));

            Map<Long, List<User>> userIdUserListMap = userMapper.selectList(
                            Wrappers.<User>lambdaQuery()
                                    .in(User::getId,userIdList)
                    )
                    .stream()
                    .collect(Collectors.groupingBy(User::getId));

            List<User> finalUserList = new ArrayList<>();
            for (Long itemUserId : userIdList) {
                finalUserList.add(userIdUserListMap.get(itemUserId).get(0));
                saveRecommendation(user.getId(), itemUserId);
            }

            String redisKey = String.format("yupao:user:recommend:%s", userId);
            ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
            // 写缓存
            try {
                valueOperations.set(redisKey, finalUserList, 30000, TimeUnit.MILLISECONDS);
            } catch (Exception e) {
            }

            //方式二
            // 使用当天日期作为随机种子
            /*long dailySeed = LocalDate.now().toEpochDay();
            Random dailyRandom = new Random(dailySeed + user.getId());

            // 计算匹配分数并排序
            candidates.sort((p1, p2) -> {
                double score1 = calculateMatchScore(user, p1);
                double score2 = calculateMatchScore(user, p2);
                return Double.compare(score2, score1); // 降序
            });

            // 选择前N个，加入一些随机性
            List<User> selected = new ArrayList<>();
            for (int i = 0; i < Math.min(count, candidates.size()); i++) {
                // 加入随机性，不完全按分数
                int index = i + (dailyRandom.nextInt(3) - 1); // -1, 0 或 +1
                index = Math.max(0, Math.min(index, candidates.size() - 1));
                User selectedPerson = candidates.get(index);
                selected.add(selectedPerson);

                // 保存推荐记录
                saveRecommendation(user.getId(), selectedPerson.getId());
            }*/
        }
        return Boolean.TRUE;
    }

    private void saveRecommendation(Long userId, Long personId){
        RecommendHistory recommendHistory = new RecommendHistory();
        recommendHistory.setUserId(userId);
        recommendHistory.setPersonId(personId);
        recommendHistory.setRecommendDate(LocalDate.now());
        recommendHistoryMapper.insert(recommendHistory);
    }

    // 计算用户和推荐人员的匹配分数
    private double calculateMatchScore(User user, User person) {
        double score = 0;

        //可以自行扩展
        // 行业匹配
        /*if (user.getIndustry().equals(person.getIndustry())) {
            score += 30;
        }*/

        // 兴趣匹配
        Gson gson = new Gson();
        List<String> tagList = gson.fromJson(user.getTags(), new TypeToken<List<String>>() {}.getType());
        List<String> personTagList = gson.fromJson(person.getTags(), new TypeToken<List<String>>() {}.getType());
        long commonInterests = tagList.stream()
                .filter(personTagList::contains)
                .count();
        score += commonInterests * 20;

        // 年龄相近
        /*int ageDiff = Math.abs(user.getAge() - person.getAge());
        score += Math.max(0, 20 - ageDiff);*/

        return score;
    }

    // 获取用户已推荐的人员ID(最近30天内)
    private Map<Long, List<RecommendHistory>> getUserRecommendHistoryMap(Set<Long> userIdSet){
        Map<Long, List<RecommendHistory>> userRecommendHistoryMap = recommendHistoryMapper.selectList(
                Wrappers.<RecommendHistory>lambdaQuery()
                        .in(RecommendHistory::getUserId, userIdSet)
                        .ge(RecommendHistory::getRecommendDate, LocalDate.now())
        ).stream().collect(Collectors.groupingBy(RecommendHistory::getUserId));
        return userRecommendHistoryMap;
    }
}
